package com.spring.mvc.util.xml;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.xml.sax.InputSource;

import com.spring.mvc.util.StringUtil;

public class JXmlUtil {

	private static Format _oneLineformat;
	private static Format _multiLineformat;

	public static Document newDocument() {
		return new Document();
	}

	public static final Element newDocument(String name) {
		Document doc;
		try {
			doc = new Document();
			Element root = new Element(name);
			doc.addContent(root);
			return root;
		} catch (Exception e) {
			return null;
		}
	}

	public static final Element newElement(Element parent, String name) {
		Element element = new Element(name);

		parent.addContent(element);

		return element;
	}

	public static final Element newElement(Element parent, String name,
			Hashtable<?, ?> attrs) {
		Element element = new Element(name);
		parent.addContent(element);
		if (attrs != null) {
			for (Iterator<?> localIterator = attrs.keySet().iterator(); localIterator
					.hasNext();) {
				Object key = localIterator.next();
				String attrname = key.toString();
				String attrvalue = attrs.get(key).toString();

				element.setAttribute(attrname, attrvalue);
			}
		}
		return element;
	}

	public static final Element child(Element parent, String nameid) {
		List<Element> nodes = parent.getChildren(nameid);

		if (nodes != null && nodes.size() == 1) {
			return nodes.get(0);
		}
		throw new RuntimeException("Cann't found node");
	}

	public static final List<Element> children(Element parent, String nameid) {
		return parent.getChildren(nameid);
	}

	public static String xml2String(Element root, String charset) {
		return xml2String(root, getOnelineXmlFormat(charset));
	}

	public static String xml2String(Document doc, String charset) {
		return xml2String(doc, getOnelineXmlFormat(charset));
	}

	public static String xml2String(Element root, Format format) {
		Element tmp = root.clone();

		tmp.detach();

		Document doc = new Document(tmp);

		return xml2String(doc, format);
	}

	public static String xml2String(Document doc, Format format) {
		XMLOutputter out;
		try {
			out = new XMLOutputter();
			out.setFormat(format);

			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			out.output(doc, baos);

			return baos.toString();
		} catch (IOException e) {
			throw new RuntimeException("xml cast exceptioin", e);
		}
	}

	public static Element string2Xml(String xml) {
		SAXBuilder builder;
		try {
			builder = new SAXBuilder();

			InputSource is = new InputSource(new StringReader(xml));

			Document doc = builder.build(is);

			return doc.getRootElement();
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static Element file2Xml(File file) {
		SAXBuilder builder;
		try {
			builder = new SAXBuilder();

			Document doc = builder.build(file);
			return doc.getRootElement();
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	public static void xml2File(String file, Element elmRoot) {
		BufferedWriter bw = null;
		try {
			elmRoot.detach();
			Format myFmt = Format.getCompactFormat();
			myFmt.setEncoding("gbk");
			myFmt.setIndent("    ");
			myFmt.setLineSeparator("\r\n");

			XMLOutputter fmt = new XMLOutputter(myFmt);

			Document doc = new Document();
			doc.setRootElement(elmRoot);

			String ss = "";
			ss = fmt.outputString(doc);
			ss.replaceAll("\n\n", "\n");

			bw = new BufferedWriter(new FileWriter(new File(file)));
			bw.write(ss);
			bw.close();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (bw != null) {
					bw.close();
					bw = null;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public static void xml2File(String file, JXmlWapper wapper) {
		BufferedWriter bw = null;
		try {
			Element elmRoot;
			elmRoot = wapper.getXmlRoot();
			elmRoot.detach();

			Format myFmt = Format.getCompactFormat();
			myFmt.setEncoding("gbk");
			myFmt.setIndent("    ");
			myFmt.setLineSeparator("\r\n");

			XMLOutputter fmt = new XMLOutputter(myFmt);

			Document doc = new Document();
			doc.setRootElement(elmRoot);

			String ss = "";
			ss = fmt.outputString(doc);
			ss.replaceAll("\n\n", "\n");

			bw = new BufferedWriter(new FileWriter(new File(file)));
			bw.write(ss);
			bw.close();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (bw != null) {
					bw.close();
					bw = null;
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public static Element url2Xml(String url, String data) throws IOException,
			JDOMException {
		return url2Xml(url, data, 10);
	}

	public static Element url2Xml(String url, String data, int timeout)
			throws IOException, JDOMException {
		String line;
		URL murl = new URL(url);
		HttpURLConnection con = (HttpURLConnection) murl.openConnection();
		con.setConnectTimeout(1000 * timeout);
		con.setReadTimeout(1000 * timeout);

		con.setDoInput(true);
		con.setDoOutput(true);
		con.setAllowUserInteraction(false);

		DataOutputStream posts = new DataOutputStream(con.getOutputStream());
		posts.writeBytes(data);
		posts.flush();

		BufferedReader br = new BufferedReader(new InputStreamReader(con
				.getInputStream()));
		StringBuilder b = new StringBuilder();

		while ((line = br.readLine()) != null) {
			b.append(line);
			b.append("\r\n");
		}

		br.close();
		posts.close();

		con.disconnect();
		br = null;
		con = null;
		posts = null;

		SAXBuilder builder = new SAXBuilder();
		Reader in = new StringReader(new String(b));
		Document doc = builder.build(in);

		return doc.getRootElement();
	}

	public static Element url2Xml(String url, int timeout) throws Exception {
		String line;
		URL murl = new URL(url);

		HttpURLConnection con = (HttpURLConnection) murl.openConnection();
		con.setConnectTimeout(1000 * timeout);
		con.setReadTimeout(1000 * timeout);

		BufferedReader br = new BufferedReader(new InputStreamReader(con
				.getInputStream()));
		StringBuilder b = new StringBuilder();
		while ((line = br.readLine()) != null) {
			b.append(line);
			b.append("\r\n");
		}

		br.close();
		con.disconnect();
		br = null;
		con = null;

		SAXBuilder builder = new SAXBuilder();
		Reader in = new StringReader(new String(b));
		Document doc = builder.build(in);
		return doc.getRootElement();
	}

	public static Format getOnelineXmlFormat(String charset) {
		if (_oneLineformat == null) {
			_oneLineformat = Format.getRawFormat();
			_oneLineformat.setEncoding(charset);
			_oneLineformat.setLineSeparator("\r\n");
		}
		return _oneLineformat;
	}

	public static Format getMultilineXmlFormat(String charset) {
		if (_multiLineformat == null) {
			_multiLineformat = Format.getRawFormat();
			_multiLineformat.setEncoding(charset);
			_multiLineformat.setIndent("  ");
		}
		return _multiLineformat;
	}

	public static String decode(String strSource) {
		if (strSource == null)
			return "";

		String strDest = strSource;
		strDest = StringUtil.replaceString(strSource, "&lt;", "<");
		strDest = StringUtil.replaceString(strSource, "&gt;", ">");
		strDest = StringUtil.replaceString(strSource, "&amp;", "&");
		strDest = StringUtil.replaceString(strSource, "&quot;", "\"");

		return strDest;
	}

	public static String encode(String strSource) {
		if (strSource == null)
			return "";

		String strDest = strSource;
		strDest = StringUtil.replaceString(strDest, "&", "&amp;");
		strDest = StringUtil.replaceString(strDest, "<", "&lt;");
		strDest = StringUtil.replaceString(strDest, ">", "&gt;");
		strDest = StringUtil.replaceString(strDest, "\"", "&quot;");

		return strDest;
	}

	public static String createTagXml(String tagName, String tagValue) {
		StringBuffer sb = new StringBuffer("");
		sb.append("<");
		sb.append(encode(tagName));
		if (tagValue.length() == 0) {
			sb.append("/>");
		} else {
			sb.append(">");
			sb.append(encode(tagValue));
			sb.append("</");
			sb.append(tagName);
			sb.append(">");
		}
		return new String(sb);
	}

	public static String createAttrXml(String attrName, String attrValue) {
		StringBuffer sb = new StringBuffer("");
		sb.append(encode(attrName));
		sb.append("=\"");
		sb.append(encode(attrValue));
		sb.append("\" ");
		return new String(sb);
	}
}
